//
//  ServerNetworkCenter.m
//  Karaoke
//
//  Created by Ka Leung Ke on 11-10-17.
//  Copyright 2011年 __MyCompanyName__. All rights reserved.
//

#import "ServerNetworkCenter.h"
#import "ClientNetworkCenter.h"
#import "DataCenter.h"
#include <netdb.h>
#include <arpa/inet.h>

@implementation ServerNetworkCenter
@synthesize isConnect;

static ServerNetworkCenter *_sharedInstance;

+ (ServerNetworkCenter *)sharedInstance
{
    if (!_sharedInstance)
    {
        _sharedInstance = [[ServerNetworkCenter alloc] init];
    }

    return _sharedInstance;
}

- (id)init
{
    self = [super init];

    if (self)
    {
        // Initialization code here.
        isConnect = NO;
        receiveData = [[NSMutableData alloc] init];
        dataOffset = 0;
        encGBK = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
    }

    return self;
}

- (void)initConnect
{
    if ([ClientNetworkCenter sharedInstance].isConnect == YES)
    {
        [[ClientNetworkCenter sharedInstance] disconnectToServer];
    }

    [receiveData setLength:0];
    dataOffset = 0;
    mainSocket = [[AsyncSocket alloc] initWithDelegate:self];

    NSError *err = nil;

    NSString    *tempServerIp = [[NSUserDefaults standardUserDefaults] stringForKey:@"Server_Ip"];
    int         tempServerPort = [[[NSUserDefaults standardUserDefaults] stringForKey:@"Server_Port"] intValue];
    NSString    *serverIP = [self getIPAddressByHostName:tempServerIp];
    NSLog(@"trying to connect server ip: %@, port: %i", serverIP, tempServerPort);

    if ([mainSocket connectToHost:serverIP onPort:tempServerPort withTimeout:2 error:&err])
    {}
    else
    {
        NSLog(@"Fail to develop connection");
    }
}

- (NSString *)getIPAddressByHostName:(NSString *)strHostName
{
    // NSString to char*
    const char *webSite = [strHostName cStringUsingEncoding:NSASCIIStringEncoding];

    // Get host entry info for given host
    struct hostent *remoteHostEnt = gethostbyname(webSite);

    // Get address info from host entry
    struct in_addr *remoteInAddr = (struct in_addr *)remoteHostEnt->h_addr_list[0];

    // Convert numeric addr to ASCII string
    char *sRemoteInAddr = inet_ntoa(*remoteInAddr);

    // char* to NSString
    NSString *ip = [[[NSString alloc]   initWithCString :sRemoteInAddr
                                        encoding        :NSASCIIStringEncoding] autorelease];

    return ip;
}

- (void)sentMsgAskForUpdate
{
    NSLog(@"sent msg ask for update");
    [self sentMsg:@"\r\n3\r\n"];
}

- (BOOL)getConnected
{
    return [mainSocket isConnected];
}

- (void)sentMsgAskForReg:(NSString *)tempCode
{
    NSLog(@"sent msg ask for reg");
    //    [self sentMsg:[NSString stringWithFormat:@"\r\n1\r\n%@\r\n", tempCode]];
    [self sentMsg:rtBound:tempCode, [DataCenter sharedInstance].UDID, nil];
}

- (void)disconnectToServer
{
    [mainSocket disconnect];
}

- (void)sentMsg:(NSString *)tempMsg
{
    NSData *data = [[[NSData alloc] initWithData:[tempMsg dataUsingEncoding:encGBK]] autorelease];

    NSMutableData *buf = [[NSMutableData alloc] initWithData:
        [[NSString stringWithFormat:@"%0.6i", [data length] + 1 + 6] dataUsingEncoding:encGBK]];

    [buf appendData:data];

    UInt8 tempCRCChar = [self getCRC:buf.bytes:buf.length];

    //    CLog(@"gen CRC %c", tempCRCChar);
    [buf appendBytes:&tempCRCChar length:1];

    //    CLog(@"sent out msg: %@ and data: %@", tempFinalString, tempFinalData);
    [mainSocket writeData:buf withTimeout:5 tag:0];
    [buf release];
}

- (void)sentMsg:(int)cmd:(NSString *)para, ...
    {
    NSMutableString *temp = [NSMutableString stringWithFormat:@"\r\n%d\r\n", cmd];

    if (para)
    {
        [temp appendFormat:@"%@\r\n", para];
        id      arg;
        va_list argList;
        va_start(argList, para);

        while ((arg = va_arg(argList, id)))
        {
            [temp appendFormat:@"%@\r\n", arg];
        }

        va_end(argList);
    }

    [self sentMsg:temp];
}

- (void)sendMsg:(int)cmd:(NSArray *)para
{
    NSString *temp = [NSString stringWithFormat:@"\r\n%d\r\n%@", cmd, [para componentsJoinedByString:@"\r\n"]];

    [self sentMsg:temp];
}

- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
    //    CLog(@"Did write the data");
}

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    CLog(@"receive data: %@", data);
    [receiveData appendData:data];

    while (receiveData.length > 0)
    {
        int tempPacketSize = [[[NSString alloc] initWithData:[receiveData subdataWithRange:NSMakeRange(0, 6)] encoding:NSUTF8StringEncoding]  autorelease].intValue;

        if (tempPacketSize > receiveData.length)
        {
            CLog(@"数据接收不完整，等待内容");
            break;
        }

        if ([self checkIfVaildMsg:[receiveData subdataWithRange:NSMakeRange(0, tempPacketSize)]])
        {
            NSString *msg = [[[NSString alloc] initWithData:[receiveData subdataWithRange:NSMakeRange(0, tempPacketSize - 1)] encoding:encGBK] autorelease];

            CLog(@"ServerNetwork have receive msg:%@", msg);
            [[DataCenter sharedInstance] forwardNoticeCode:@"tcpMsg" detail:msg];
        }
        else
        {
            CLog(@"error wrong key again length: %i and data: %@", [data length], data);
        }

        //删除已经处理过的内容
        if (receiveData.length - tempPacketSize == 0)
        {
            receiveData.length = 0;
        }
        else
        {
            [receiveData replaceBytesInRange:NSMakeRange(0, tempPacketSize) withBytes:NULL length:0];
        }
    }

    [mainSocket readDataWithTimeout:-1 tag:0];
}

- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
    CLog(@"did connect to server");
    [[DataCenter sharedInstance] forwardNoticeCode:@"sysMsg" detail:@"serverConnected"];
    [mainSocket readDataWithTimeout:-1 tag:0];
    isConnect = YES;
}

- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{}

- (void)onSocketDidDisconnect:(AsyncSocket *)sock
{
    CLog(@"did disconnect already");
    [[DataCenter sharedInstance] forwardNoticeCode:@"sysMsg" detail:@"serverDidDisconnect"];
    isConnect = NO;
}

- (BOOL)checkIfVaildMsg:(NSData *)tempData
{
    const unsigned char *buf = tempData.bytes;
    UInt8               tempCRCOriginalChar = buf[tempData.length - 1];
    //    UInt8 *tempCRCOriginalChar = (UInt8 *)[[tempData subdataWithRange:NSMakeRange([tempData length] - 1, 1)] bytes];

    //    UInt8 tempCRCChar = [self getCRC:[tempData subdataWithRange:NSMakeRange(0, [tempData length] - 1)]];
    UInt8 tempCRCChar = [self getCRC:buf:tempData.length - 1];

    if (tempCRCChar == tempCRCOriginalChar)
    {
        CLog(@"CRC corrent");
        return YES;
    }

    return NO;
}

- (UInt8)getCRC:(const unsigned char *)buf:(int)len
{
    //    const unsigned char *buf = [data bytes];

    UInt8 crc = 0;

    //    int len = data.length;
    for (int j = 0; j < len; j++)
    {
        crc ^= buf[j];

        for (int i = 0; i < 8; i++)
        {
            if (crc & 0x01)
            {
                crc = (crc >> 1)^0x8C;
            }
            else
                crc >>= 1;
        }
    }

    return crc;
}

- (NSString *)getBoundCode
{
    NSString *path = [[NSBundle mainBundle] pathForResource:@"BoundCode.plist"ofType:@""];
    // 获取数据
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
    NSString            *code = [dict objectForKey:@"BoundCode"];

    NSLog (@"%@", code);
    return code;
}

- (void)updateBoundCode:(NSString *)codeString
{
    NSString            *path = [[NSBundle mainBundle] pathForResource:@"BoundCode.plist"ofType:@""];
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];

    [dict setObject:codeString forKey:@"BoundCode"];
    [dict writeToFile:path atomically:YES];
}

@end
